package cn.com.anysdk.ocr.service.impl;

import cn.com.anysdk.ocr.config.OcrProperties;
import cn.com.anysdk.ocr.exception.OcrException;
import cn.com.anysdk.ocr.model.OcrOptions;
import cn.com.anysdk.ocr.model.OcrResult;
import cn.com.anysdk.ocr.service.IOcrService;
import com.aliyun.ocr_api20210707.Client;
import com.aliyun.ocr_api20210707.models.RecognizeBasicRequest;
import com.aliyun.ocr_api20210707.models.RecognizeBasicResponse;
import com.aliyun.ocr_api20210707.models.RecognizeBasicResponseBody;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
import lombok.extern.slf4j.Slf4j;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

/**
 * 阿里云 OCR 服务实现
 */
@Slf4j
public class
AliyunOcrService implements IOcrService {

    private final OcrProperties properties;
    private final Client client;

    public AliyunOcrService(OcrProperties properties) {
        log.info("AliyunOcrService 初始化，配置：{}", properties);
        this.properties = validateProperties(properties);
        this.client = createClient();
    }

    /**
     * 验证配置属性
     */
    private OcrProperties validateProperties(OcrProperties properties) {
        if (properties == null) {
            throw new OcrException("OCR properties cannot be null");
        }
        if (properties.getAliyun() == null) {
            throw new OcrException("Aliyun OCR properties cannot be null");
        }
        if (properties.getAliyun().getAccessKeyId() == null || properties.getAliyun().getAccessKeyId().trim().isEmpty()) {
            throw new OcrException("Aliyun access key ID cannot be empty");
        }
        if (properties.getAliyun().getAccessKeySecret() == null || properties.getAliyun().getAccessKeySecret().trim().isEmpty()) {
            throw new OcrException("Aliyun access key secret cannot be empty");
        }
        if (properties.getAliyun().getRegion() == null || properties.getAliyun().getRegion().trim().isEmpty()) {
            throw new OcrException("Aliyun region cannot be empty");
        }
        return properties;
    }

    /**
     * 创建阿里云 OCR 客户端
     */
    private Client createClient() {
        try {
            Config config = new Config()
                    .setAccessKeyId(properties.getAliyun().getAccessKeyId())
                    .setAccessKeySecret(properties.getAliyun().getAccessKeySecret());
            config.endpoint = "ocr-api." + properties.getAliyun().getRegion() + ".aliyuncs.com";
            return new Client(config);
        } catch (Exception e) {
            log.error("Failed to create Aliyun OCR client", e);
            throw new OcrException("Failed to create Aliyun OCR client", e);
        }
    }

    @Override
    public OcrResult recognize(File file, OcrOptions options) {
        try {
            log.debug("Recognizing image from file: {}", file.getAbsolutePath());
            byte[] imageBytes = java.nio.file.Files.readAllBytes(file.toPath());
            return recognize(imageBytes, options);
        } catch (IOException e) {
            log.error("Failed to read image file: {}", file.getAbsolutePath(), e);
            throw new OcrException("Failed to read image file: " + file.getAbsolutePath(), e);
        }
    }

    @Override
    public OcrResult recognize(InputStream inputStream, OcrOptions options) {
        try {
            log.debug("Recognizing image from input stream");
            byte[] imageBytes = inputStream.readAllBytes();
            return recognize(imageBytes, options);
        } catch (IOException e) {
            log.error("Failed to read image from input stream", e);
            throw new OcrException("Failed to read image from input stream", e);
        }
    }

    @Override
    public OcrResult recognize(byte[] imageBytes, OcrOptions options) {
        try {
            log.debug("Recognizing image from byte array, size: {} bytes", imageBytes.length);
            RecognizeBasicRequest request = new RecognizeBasicRequest()
                    .setBody(new ByteArrayInputStream(imageBytes))
                    .setNeedRotate(options.isDetectOrientation());

            RecognizeBasicResponse response = client.recognizeBasicWithOptions(request, new RuntimeOptions());
            return convertToOcrResult(response.getBody());
        } catch (Exception e) {
            log.error("Failed to recognize image from byte array", e);
            throw new OcrException("Failed to recognize image from byte array", e);
        }
    }

    @Override
    public OcrResult recognize(String url, OcrOptions options) {
        try {
            log.debug("Recognizing image from URL: {}", url);
            RecognizeBasicRequest request = new RecognizeBasicRequest()
                    .setUrl(url)
                    .setNeedRotate(options.isDetectOrientation());

            RecognizeBasicResponse response = client.recognizeBasicWithOptions(request, new RuntimeOptions());
            return convertToOcrResult(response.getBody());
        } catch (Exception e) {
            log.error("Failed to recognize image from URL: {}", url, e);
            throw new OcrException("Failed to recognize image from URL: " + url, e);
        }
    }

    /**
     * 将阿里云 OCR 响应转换为 OcrResult
     */
    private OcrResult convertToOcrResult(RecognizeBasicResponseBody body) {
        OcrResult result = new OcrResult();
        String dataStr = body.getData();
        if (dataStr != null && !dataStr.isEmpty()) {
            try {
                JSONObject dataJson = JSON.parseObject(dataStr);
                result.setText(dataJson.getString("content"));
                result.setConfidence(dataJson.getFloat("prism_confidence"));
                result.setOrientation(dataJson.getFloat("angle"));
                // prism_wordsInfo 是文本块信息
                if (dataJson.containsKey("prism_wordsInfo")) {
                    // TODO: 你可以根据 OcrResult.OcrBlock 的结构进一步完善
                    // 这里只是简单存储原始 JSON
                    result.setBlocks(null); // 或者你可以解析为 List<OcrResult.OcrBlock>
                }
            } catch (Exception e) {
                log.error("Failed to parse OCR response data: {}", dataStr, e);
                throw new OcrException("Failed to parse OCR response data", e);
            }
        }
        return result;
    }
}